#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <unistd.h>
#include <iomanip>
#include <stdlib.h>
//#include <string.h>
//#include <stdio.h>
#include <iostream>
#include "eth_frame.h"
#include "ip_frame.h"  
#include "udp_frame.h"
#include "tcp_frame.h"

using std::cout;
using std::endl;

int engine(unsigned int opt, int *sock_, int *rc_);
unsigned int init(int argc_, char **argv_);

int main(int argc, char **argv){
	int sock, rc;  // с ним связываем наш интерфейс
	
	sock = socket(AF_PACKET,SOCK_PACKET,htons(ETH_P_ALL));
	rc = setsockopt(sock,SOL_SOCKET, SO_BINDTODEVICE,"eth0",4); // связывание интерфейса
	if (rc) {
		cout << "false" << endl;
		return 1;
	}
	cout << "rc true" << endl;
	engine(init(argc, argv), &sock, &rc);
	close(sock);
	return 0;
};
unsigned int init(int argc_, char **argv_){
	int arguments = 0;
	unsigned int options = 0, pr = 0;
	opterr = 0; 
	while ((arguments = getopt(argc_, argv_, "p:l:d:")) != -1) {
		switch (arguments){
		case 'p': 
			cout << "Using filter -p in activ: " << optarg << endl;
			pr = atoi(optarg);
			options |= (pr << 8);
			options |= 2;
			break;
		case 'l':
			cout << "Using filter -l in activ(level): " << optarg << endl;
			if (atoi(optarg) == 0) ;
			else if (atoi(optarg) == 1) options |= ( 1 << 5);
			else if (atoi(optarg) == 10) options |= (2 << 5);
			else if (atoi(optarg) == 11) options |= (3 << 5);
			else if (atoi(optarg) == 100) options |= (4 << 5);
			else if (atoi(optarg) == 101) options |= (5 << 5);
			else if (atoi(optarg) == 110) options |= (6 << 5);
			else if (atoi(optarg) == 111) options |= (7 << 5);
			else  {
				cout << "invalid argument" << endl;
				return 1;
			};
			break;
		case 'd':
			cout << "Using filter -d in activ (otobrazit dannie): " << optarg << endl;
			if (atoi(optarg) == 0) ;
			else if (atoi(optarg) == 1) options |= ( 1 << 2);
			else if (atoi(optarg) == 10) options |= (2 << 2);
			else if (atoi(optarg) == 11) options |= (3 << 2);
			else if (atoi(optarg) == 100) options |= (4 << 2);
			else if (atoi(optarg) == 101) options |= (5 << 2);
			else if (atoi(optarg) == 110) options |= (6 << 2);
			else if (atoi(optarg) == 111) options |= (7 << 2);
			else  {
				cout << "invalid argument" << endl;
				return 1;
			};
			break;
		};
	};
	return options;
};

int engine(unsigned int opt, int *sock_, int *rc_)
{
	unsigned char buf[LENETH];
	eth_frame frame;
	ip_frame ipfr;
	tcp tcpfr;
	udp udpfr;
	int i, bt;
	int *tmp;
	//opt |= 128;				// Для отладки
	unsigned int port = 0;
	port = opt >> 8;
	for(int count = 0;;count++) {
		*rc_ = recvfrom(*sock_,buf,sizeof(buf),0,0,0);
		//cout << endl << count;
		frame.incapeth(buf,*rc_);
		cout << endl <<  "#####################################################";
					// ETHERNET заголовок
		if (128 & opt){
			// знач тут отображаем информацию о заголовках
			cout << endl << "+---------------------------------------------------+";
			cout << endl << "|                ETHERNET FRAME                     |";
			cout << endl << "+----------------------+----------------------------+";
			cout << endl << "| MAC destination      | ";
			tmp = frame.getmacd();
			cout.setf(std::ios::uppercase);
			for (i = 0; i < 6; i++){
				cout << std::setw(2) << std::setfill('0') << std::hex << tmp[i];
				if (i < 5) cout << ":";
			};
			cout << "          |";
			cout << endl << "| MAC source           | ";
			tmp = frame.getmacs();
			cout.setf(std::ios::uppercase);
			for (i = 0; i < 6; i++){
				cout << std::setw(2) << std::setfill('0') << std::hex << tmp[i];
				if (i < 5) cout << ":";
			};
			cout << "          |";
			cout << endl << "| CRC                  | ";
			cout << std::setw(17) << std::setfill(' ') << std::dec << frame.getcrc();
			cout << "          |"; 
			cout << endl << "| Type incapsulation   | ";
			cout << std::setw(17) << std::setfill(' ')<< std::hex << frame.getethtype() ;
			cout << "          |";
			cout << endl << "+----------------------+----------------------------+";
			cout << std::dec;
			cout.unsetf(std::ios::uppercase);
		};
					// Данные ETHERNET
		if (16 & opt){
			bt = 1;
			cout << endl << "+----------------------+----------------------------+";
			cout << endl << "| ";
			for (i=0; i < frame.getlendata(); i++){
				cout.setf(std::ios::uppercase);
				cout << std::setw(2) << std::setfill('0') << std::hex << frame.data[i];
				if (bt == 8) cout << "   ";
				else if (bt == 16) {
					bt = 0;
					cout << " |";
					if (i != (frame.getlendata()-1)) cout << endl << "| ";
				} else cout << " ";
				bt++;
				if ((i == (frame.getlendata()-1)) && (bt != 1)) {
					int j = (frame.getlendata()%16);
					if (j <= 8) j=j*3;
					else j=j*3 +2;
					cout << std::setw(51-j) << std::setfill(' ') << "|";
				};
			};
			cout << endl << "+---------------------------------------------------+";
			cout << std::dec;
			cout.unsetf(std::ios::uppercase);			
		};
					// Если тип передаваемому протоколу IP
		if (frame.getethtype() == ETHERTYPE) {
			ipfr.incapip(frame.data,frame.getlendata());
					// значит отобразить заголовок IP
			if (64 & opt){			
				cout << endl << "+---------------------------------------------------+";
				cout << endl << "|               INTERNET PROTOCOL                   |";
				cout << endl << "+----------------------+----------------------------+";
				cout << endl << "| Version IP           | ";
				cout << std::setw(17) << std::setfill(' ') << ipfr.getversion();
				cout << "          |";
				cout << endl << "| length head          | "; 
				cout << std::setw(17) << std::setfill(' ') << ipfr.getsizehead();
				cout << "          |";
				cout << endl << "| servis in hex        | ";
				cout << std::setw(17) << std::setfill(' ') << std::hex << ipfr.getservis();
				cout << "          |";
				cout << endl << "| length packet        | ";
				cout << std::setw(17) << std::setfill(' ') << std::dec << ipfr.getsizepack();
				cout << "          |";
				cout << endl << "| identificator        | ";
				cout << std::setw(17) << std::setfill(' ') << std::hex << ipfr.getidentif();
				cout << "          |";
				cout << endl << "| flags                | ";
				cout << std::setw(17) << std::setfill(' ') << std::hex << ipfr.getflags();
				cout << "          |";
				cout << endl << "| fragmen identif      | ";
				cout << std::setw(17) << std::setfill(' ') << std::hex << ipfr.getsfrag();
				cout << "          |";
				cout << endl << "| time live TTL        | ";
				cout << std::setw(17) << std::setfill(' ') << std::dec << ipfr.gettimeTTL();
				cout << "          |";
				cout << endl << "| protocol up          | ";
				cout << std::setw(17) << std::setfill(' ') << std::dec << ipfr.getprot();
				cout << "          |";
				cout << endl << "| controlsum head      | ";
				cout << std::setw(17) << std::setfill(' ') << ipfr.getcontrolsum();
				cout << "          |";
				cout << endl << "| ip source            | ";
				cout << std::setw(17) << std::setfill(' ') << ipfr.getipsource();
				cout << "          |";
				cout << endl << "| ip destination       | ";
				cout << std::setw(17) << std::setfill(' ') << ipfr.getipdestin();
				cout << "          |";				
				cout << endl << "+----------------------+----------------------------+";
				cout << std::dec;
				cout.unsetf(std::ios::uppercase);
			};
					// Отобразить данные несущие пакеты IP
			if (8 & opt) {
				bt = 1;
				cout << endl << "+----------------------+----------------------------+";
				cout << endl << "| ";
				for (i=0; i < ipfr.getlendata(); i++){
					cout.setf(std::ios::uppercase);
					cout << std::setw(2) << std::setfill('0') << std::hex << ipfr.data[i];
					if (bt == 8) cout << "   ";
					else if (bt == 16) {
						bt = 0;
						cout << " |";
						if (i != (ipfr.getlendata()-1)) cout << endl << "| ";
					} else cout << " ";
					bt++;
					if ((i == (ipfr.getlendata()-1)) && (bt != 1)) {
						int j = (ipfr.getlendata()%16);
						if (j <= 8) j=j*3 + 2;
						else j=j*3 +2;
						cout << std::setw(51-j) << std::setfill(' ') << "|";
					};
				};
				cout << endl << "+---------------------------------------------------+";	
				cout << std::dec;
				cout.unsetf(std::ios::uppercase);
			};
					// Протокол транспортного уровня
			if ((32 & opt) || (4 & opt) || (2 & opt)){	
					// Если TCP
				if (ipfr.getprot() == 6) {
					tcpfr.tcpincap(ipfr.data, ipfr.getlendata());
					// Если отобразить заголовок
					if (32 & opt) {
						cout << endl << "+---------------------------------------------------+";
						cout << endl << "|           TRANSMISSION CONTROL PROTOCOL           |";
						cout << endl << "+----------------------+----------------------------+";
						cout << endl << "| Port source          | ";
						cout << std::setw(17) << std::setfill(' ') << tcpfr.getports();
						cout << "          |";
						cout << endl << "| Port destination     | ";
						cout << std::setw(17) << std::setfill(' ') << tcpfr.getportd();
						cout << "          |";
						cout << endl << "| Length packet        | ";
						cout << std::setw(17) << std::setfill(' ') << tcpfr.getlendata();
						cout << "          |";
						cout << endl << "+---------------------------------------------------+";
					};
					// Если вывести данные
					if (4 & opt) {
						bt = 1;
						cout << endl << "+----------------------+----------------------------+";
						cout << endl << "| ";
						for (i=0; i < tcpfr.getlendata(); i++){
							cout.setf(std::ios::uppercase);
							cout << std::setw(2) << std::setfill('0') << std::hex << tcpfr.data[i];
							if (bt == 8) cout << "   ";
							else if (bt == 16) {
								bt = 0;
								cout << " |";
								if (i != (tcpfr.getlendata()-1)) cout << endl << "| ";
							} else cout << " ";
							bt++;
							if ((i == (tcpfr.getlendata()-1)) && (bt != 1)) {
								int j = (tcpfr.getlendata()%16);
								if (j <= 8) j=j*3;
								else j=j*3 +2;
								cout << std::setw(51-j) << std::setfill(' ') << "|";
							};
						};
						cout << endl << "+---------------------------------------------------+";					
						cout << std::dec;
						cout.unsetf(std::ios::uppercase);
					};
					//  если UDP
				} else if (ipfr.getprot() == 17){
					udpfr.udpincap(ipfr.data, ipfr.getlendata());
					// Если отобразить заголовок
					if (32 & opt){
						cout << std::dec;
						cout << endl << "+---------------------------------------------------+";
						cout << endl << "|              USER DATAGRAM PROTOCOL               |";
						cout << endl << "+----------------------+----------------------------+";
						cout << endl << "| Port source          | ";
						cout << std::setw(17) << std::setfill(' ') << udpfr.getports();
						cout << "          |";
						cout << endl << "| Port destination     | ";
						cout << std::setw(17) << std::setfill(' ') << udpfr.getportd();
						cout << "          |";
						cout << endl << "| Length packet        | ";
						cout << std::setw(17) << std::setfill(' ') << udpfr.getlendata();
						cout << "          |";
						cout << endl << "+---------------------------------------------------+";	
					};
					// Если отобразить данные
					if (4 & opt) {
						bt = 1;
						cout << endl << "+---------------------------------------------------+";
						cout << endl << "| ";
						for (i=0; i < udpfr.getlendata(); i++){
							cout.setf(std::ios::uppercase);
							cout << std::setw(2) << std::setfill('0') << std::hex << udpfr.data[i];
							if (bt == 8) cout << "   ";
							else if (bt == 16) {
								bt = 0;
								cout << " |";
								if (i != (udpfr.getlendata()-1)) cout << endl << "| ";
							} else cout << " ";
							bt++;
							if ((i == (udpfr.getlendata()-1)) && (bt != 1)) {
								int j = (udpfr.getlendata()%16);
								if (j <= 8) j=j*3 + 2;
								else j=j*3 +2;
								cout << std::setw(51-j) << std::setfill(' ') << "|";
							};
						};
						cout << endl << "+---------------------------------------------------+";						
						cout << std::dec;
						cout.unsetf(std::ios::uppercase);
					};
					if (2 & opt){
						
						cout << endl << "+---------------------------------------------------+";
						cout << endl << "|                  DATA PORT HEX                    |";
						cout << endl << "+---------------------------------------------------+";
						if (port == udpfr.getports()){
							cout << endl << "| incoming data                                     |";
							cout << endl << "+---------------------------------------------------+";
							cout << endl << "| ";
							bt = 1;
							for (i=0; i < udpfr.getlendata(); i++){
								cout.setf(std::ios::uppercase);
								cout << std::setw(2) << std::setfill('0') << std::hex << udpfr.data[i];
								if (bt == 8) cout << "   ";
								else if (bt == 16) {
									bt = 0;
									cout << " |";
									if (i != (udpfr.getlendata()-1)) cout << endl << "| ";
								} else cout << " ";
								bt++;
								if ((i == (udpfr.getlendata()-1)) && (bt != 1)) {
									int j = (udpfr.getlendata()%16);
									if (j < 8) j=j*3;
									else j=j*3 +2;
									cout << std::setw(51-j) << std::setfill(' ') << "|";
								};
							};
							cout << std::dec;
							cout.unsetf(std::ios::uppercase);
							cout << endl << "+---------------------------------------------------+";
						};
						if (port == udpfr.getportd()){
							cout << endl << "| Sent data                                         |";
							cout << endl << "+---------------------------------------------------+";
							cout << endl << "| ";
							bt = 1;
							for (i=0; i < udpfr.getlendata(); i++){
								cout.setf(std::ios::uppercase);
								cout << std::setw(2) << std::setfill('0') << std::hex << udpfr.data[i];
								if (bt == 8) cout << "   ";
								else if (bt == 16) {
									bt = 0;
									cout << " |";
									if (i != (udpfr.getlendata()-1)) cout << endl << "| ";
								} else cout << " ";
								bt++;
								if ((i == (udpfr.getlendata()-1)) && (bt != 1)) {
									int j = (udpfr.getlendata()%16);
									if (j < 8) j=j*3;
									else j=j*3 +2;
									cout << std::setw(51-j) << std::setfill(' ') << "|";
								};
							};
							cout << std::dec;
							cout.unsetf(std::ios::uppercase);						
							cout << endl << "+---------------------------------------------------+";
						};
					};
				};			
			};
		};
		cout << std::flush;
		// Сделать выход из цикла по нажатию клавишь
	}
	return 0;
};

